package controller

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

const APPID = 2156348148
const APPKEY = "XFpS522Lm1kPcAQ3"
const OCRURL = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat"

type Param struct {
	key   string
	value string
}

type RequestData struct {
	AppId     int
	TimeStamp int
	NonceStr  string
	Sign      string
	Session   string
	Question  string
}

type Response struct {
	Ret  int    `json:"ret"`
	Msg  string `json:"msg"`
	Data struct {
		Session string `json:"session"`
		Answer  string `json:"answer"`
	} `json:"data"`
}

func GetSign(params []Param) string {
	sort.Slice(params, func(i, j int) bool {
		return params[i].key < params[j].key
	})
	var s string
	for _, param := range params {
		if len(param.value) > 0 {
			s += fmt.Sprintf("%s=%s&", param.key, url.QueryEscape(param.value))
		}
	}
	s += fmt.Sprintf("app_key=%s", APPKEY)

	data := []byte(s)
	dataSum := md5.Sum(data)
	s = fmt.Sprintf("%x", dataSum)

	s = strings.ToUpper(s)
	return s
}

func GetRequestData(question string) string {
	req := RequestData{
		AppId:     APPID,
		TimeStamp: int(time.Now().Unix()),
		NonceStr:  "123456",
		Sign:      "",
		Session:   "10000",
		Question:  question,
	}
	var params []Param
	params = append(params, Param{key: "app_id", value: strconv.Itoa(req.AppId)})
	params = append(params, Param{key: "time_stamp", value: strconv.Itoa(req.TimeStamp)})
	params = append(params, Param{key: "nonce_str", value: req.NonceStr})
	params = append(params, Param{key: "sign", value: req.Sign})
	params = append(params, Param{key: "session", value: req.Session})
	params = append(params, Param{key: "question", value: req.Question})
	req.Sign = GetSign(params)
	result := ""
	for _, param := range params {
		if param.key == "sign" {
			result += fmt.Sprintf("sign=%s&", req.Sign)
		} else if len(param.value) > 0 {
			result += fmt.Sprintf("%s=%s&", param.key, url.QueryEscape(param.value))
		}
	}
	if len(result) > 1 {
		result = result[0 : len(result)-1]
	}
	return result
}

func QuestionRequest(question string) (Response, error) {
	query := GetRequestData(question)
	request, err := http.NewRequest("POST", OCRURL, bytes.NewBufferString(query))
	if err != nil {
		return Response{}, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	client := http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return Response{}, err
	}
	defer response.Body.Close()
	var rsp Response
	err = json.NewDecoder(response.Body).Decode(&rsp)
	if err != nil {
		aa, _ := ioutil.ReadAll(response.Body)
		log.Println(aa)
		return Response{}, err
	}
	return rsp, nil
}

func AIChat(c *gin.Context) {
	c.HTML(http.StatusOK, "aichat.html", gin.H{
		"content":          gin.H{},
		"HideRightSidebar": true,
	})
}

func AIChatQuestion(c *gin.Context) {
	text := c.DefaultQuery("text", "")
	if len(text) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "text is empty",
		})
		return
	}

	rsp, err := QuestionRequest(text)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}

	if rsp.Ret != 0 {
		c.JSON(http.StatusOK, gin.H{
			"msg": rsp.Msg,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"session": rsp.Data.Session,
		"msg":     rsp.Data.Answer,
	})
}
